package fudan.se.project.service.advanced.account.admin;


import fudan.se.project.controller.request.OnlyIdPropertyRequest;
import fudan.se.project.controller.response.BaseResponse;
import fudan.se.project.controller.response.ConferencesGetResponse;
import fudan.se.project.domain.User;
import fudan.se.project.domain.conference.Conference;
import fudan.se.project.domain.conference.Conference.ConferenceState;
import fudan.se.project.domain.conference.role.PcMember;
import fudan.se.project.service.infrastructure.entity.conference.ConferenceService;
import fudan.se.project.service.infrastructure.entity.conference.role.PcMemberService;
import fudan.se.project.util.http.ResponseWrapperUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;

import java.util.List;

import static fudan.se.project.repository.projection.ConferenceProjection.project;


/**
 * @author Gao Longchao
 */
@Service
public class AdminActionService {

    private final ConferenceService conferenceService;
    private ResponseWrapperUtil responseWrapperUtil;
    private PcMemberService pcMemberService;

    private static final String ARGUMENTS_ERROR="arguments error";
    private static final String SUCCESS="success";

    @Autowired
    public AdminActionService(
            ConferenceService conferenceService,
            ResponseWrapperUtil responseWrapperUtil,
            PcMemberService pcMemberService) {
        this.conferenceService = conferenceService;
        this.responseWrapperUtil = responseWrapperUtil;

        this.pcMemberService = pcMemberService;
    }

    /**
     * Queries all conferences from the ConferenceRepository
     *
     * @param state the string describing the state of a conference.
     * @param page  the page index.
     * @return a responseBody wrapped by ResponseWrapperUtil.
     */
    @PreAuthorize("hasAuthority('ADMIN')")
    public ResponseEntity<?> getConferences(int state, int page, int itemsPerPage) {

        if (state < 0 || state > 2) {
            BaseResponse baseResponse = new BaseResponse(ARGUMENTS_ERROR);
            return responseWrapperUtil.buildResponseBody(baseResponse, HttpStatus.NOT_ACCEPTABLE);
        }

        ConferencesGetResponse conferencesGetResponse;

        ConferenceState conferenceState = ConferenceState.values()[state];

        if (itemsPerPage <= 0) {
            List<Conference> conferenceList = conferenceService.findAllConferences(conferenceState);
            conferencesGetResponse = new ConferencesGetResponse(conferenceList.size(), project(conferenceList));


        } else {
            Page<Conference> conferencePage = conferenceService.
                    findAllConferencesInPage(conferenceState, page, itemsPerPage);
            conferencesGetResponse = new ConferencesGetResponse(
                    conferencePage.getTotalPages(),
                    project(conferencePage.getContent()));
        }
        conferencesGetResponse.setMessage(SUCCESS);
        return responseWrapperUtil.buildResponseBody(conferencesGetResponse, HttpStatus.OK);

    }

    /**
     * Changes the state of a conference to PASSED.
     *
     * @see ConferenceService#findById(long)
     * @see Conference.ConferenceState
     */
    @PreAuthorize("hasAuthority('ADMIN')")
    public ResponseEntity<?> confirmConference(OnlyIdPropertyRequest request) {
        return confirmOrRejectConference(request, true);
    }

    /**
     * Changes the state of a conference to REJECTED.
     *
     * @see Conference.ConferenceState
     */
    @PreAuthorize("hasAuthority('ADMIN')")
    public ResponseEntity<?> rejectConference(OnlyIdPropertyRequest request) {
        return confirmOrRejectConference(request, false);
    }

    public ResponseEntity<?> confirmOrRejectConference(OnlyIdPropertyRequest request,boolean confirm){
        Conference conference = conferenceService.findById(request.getId());
        BaseResponse baseResponse = new BaseResponse();
        if (conference == null) {
            baseResponse.setMessage(ARGUMENTS_ERROR);
            return responseWrapperUtil.buildResponseBody(baseResponse, HttpStatus.NOT_ACCEPTABLE);
        }
        else if(!conference.getState().equals(ConferenceState.APPLYING)){
            baseResponse.setMessage("conference state error");
            return responseWrapperUtil
                    .buildResponseBody(baseResponse, HttpStatus.NOT_ACCEPTABLE);
        }
        else {
            if(confirm){
                conferenceService.changeConferenceState(conference, ConferenceState.PASSED);
                User userChair = conference.getChair().getUser();
                PcMember pcMember = new PcMember(userChair, conference);
                pcMember.addTopics(conference.getTopics());
                pcMemberService.save(pcMember);
                baseResponse.setMessage(SUCCESS);
                return responseWrapperUtil.buildResponseBody(baseResponse, HttpStatus.OK);
            }
            else {
                conferenceService.changeConferenceState(conference, ConferenceState.REJECTED);
                baseResponse.setMessage(SUCCESS);
                return responseWrapperUtil.buildResponseBody(baseResponse, HttpStatus.OK);
            }
        }
    }
}
